/*
 * BplusTreeFile.h
 *
 *  Created on: Oct 31, 2012
 *      Author: m
 */

#ifndef BPLUSTREEFILE_H_
#define BPLUSTREEFILE_H_

#include <list>
#include <sstream>
#include <memory>
#include <cassert>
#include "BPlusTreeDefinitions.h"
#include "NewHandlerInterface.h"
#include "LeafNodeSerializer.h"
#include "InternalNodeSerializer.h"
#include "../bplusnodes/NewLeaf.h"
#include "../bplusnodes/NewInternal.h"
#include "../../../physical_layer/physical_layer.h"

// TODO: Estos define se pueden pasar como constantes de clase, no?
#define LEAF_LEVEL 0
#define TF_CONTROL_BLOCK_NBR 0
#define TF_INITIAL_ROOT_NBR 1
#define MAGIC_NUMBER_CODE_SIZE 2

class BPlusTreeFile : public NewHandlerInterface<NodeID_t, NodeLevel_t, DTRkey_t,
    DTRvalue_t, keyComparator_func>
{

protected:

    struct __attribute__ ((__packed__)) ControlBlock
    {
    public:
        static const char magicNumberFirstDigit;
        static const char magicNumberSecondDigit;
        char m_magicNumber[MAGIC_NUMBER_CODE_SIZE];
        size_t m_blockSize;
        NodeID_t m_rootNodeNbr;

    public:
        ControlBlock( const size_t& blockSize, const NodeID_t& rootNodeNbr );

        ControlBlock( const physical::byte* block );

        bool isValid() const;

        size_t getBlockSize() const;

        void setBlockSize( const size_t& blockSize );

        NodeID_t getRootNodeNbr() const;

        void setRootNodeNbr( const NodeID_t& rootNodeNbr );

        void writeInBlock( physical::byte* block ) const;
    };

private:
    physical::FixedSizeBlockFile m_file;
    size_t                       m_blockSize;
    LeafNodeSerializer           m_leafNodeSerializer;
    InternalNodeSerializer       m_internalNodeSerializer;

public:

    BPlusTreeFile( const string& filename, size_t blockSize = 0, bool trunc = false );

    ~BPlusTreeFile();

    node_ptr getNewRoot( const NodeLevel_t& level );

    node_ptr getRoot();

    node_ptr getNewNode( const NodeLevel_t& level );

    node_ptr getNode( const NodeID_t& nodeNbr );

    void saveNode( const node_ptr& node );

    void deleteNode( const NodeID_t& id );

private:

    void buildNode( const physical::byteStream block, node_ptr& node,
            const NodeID_t& nodeNbr );

    void registerNodeAsRoot( node_ptr& node );

    ControlBlock loadControlData();

    void saveControlData( const ControlBlock& controlBlock );

    physical::blockNumber getNewBlockNbr();

    bool fileExists( const string& filename );

    size_t autodetectBlockSize( const string& filename );

};

#endif /* BPLUSTREEFILE_H_ */
